#include "xmux.h"
#include <iostream>
extern "C" {
#include "libavformat/avformat.h"
}
using namespace std;
static void PrintErr(int err) {
  char buf[1024] = {0};
  av_strerror(err, buf, sizeof(buf) - 1);
  cerr << buf << endl;
}

#define CERR(err)                                                              \
  if (err != 0) {                                                              \
    PrintErr(err);                                                             \
    return 0;                                                                  \
  }
AVFormatContext *XMux::Open(const char *url) {
  AVFormatContext *c = nullptr;
  auto re = avformat_alloc_output_context2(&c, nullptr, nullptr, url);
  if (re < 0) {
    char buf[1024] = {0};
    av_strerror(re, buf, sizeof(buf) - 1);
    cerr << buf << endl;
    return 0;
  }
  // 添加视频音频流
  auto vs = avformat_new_stream(c, nullptr); // 视频流
  vs->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
  auto as = avformat_new_stream(c, nullptr); // 音频流
  as->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
  // 打开io
  re = avio_open(&c->pb, url, AVIO_FLAG_WRITE);
  if (re < 0) {
    char buf[1024] = {0};
    av_strerror(re, buf, sizeof(buf) - 1);
    cerr << buf << endl;
    avformat_free_context(c);
    return 0;
  }
  return c;
}

bool XMux::WriteHeader() {
  unique_lock<mutex> lock(mux_);
  if (!c_)
    return false;
  int re = avformat_write_header(c_, nullptr);
  if (re < 0) {
    char buf[1024] = {0};
    av_strerror(re, buf, sizeof(buf) - 1);
    cerr << buf << endl;
    return false;
  }
  av_dump_format(c_, 0, c_->url, 1);
  return true;
}

bool XMux::Write(AVPacket *pkt) {
  unique_lock<mutex> lock(mux_);
  if (!c_)
    return false;
  // 写入一帧数据，内部缓冲排序dts，通过pkt == NULL写入缓冲
  auto re = av_interleaved_write_frame(c_, pkt);
  CERR(re);
  return true;
}

bool XMux::WriteEnd() {
  unique_lock<mutex> lock(mux_);
  if (!c_)
    return false;
  auto re =av_interleaved_write_frame(c_, nullptr); // 写入缓冲
  CERR(re);
  re = av_write_trailer(c_);
  CERR(re);
  return true;
}
